#ifndef GLIST_H
#define GLIST_H

#include "exception.h"

template<class T>
struct Node
{
    T data_;
    struct Node* next_;

    Node(T data)
    {
        this->data_ = data;
        this->next_ = 0;
    }

    ~Node()
    {
        if (next_)
            delete this->next_;
    }
};

template<class T>
class GList
{
public:

    GList()
    {
        this->size_ = 0;
        this->head_ = 0;
    }

    ~GList()
    {
        destroy();
    }

    int size() const
    {
        return this->size_;
    }

    void destroy()
    {
        if (this->head_)
        {
            delete this->head_;
            this->head_ = 0;
            this->size_ = 0;
        }
    }

    void add(const T& data)
    {
        Node<T>* newNode = new Node<T>(data);
        Node<T>* temp = this->head_;
        if (this->head_ == 0)
            this->head_ = newNode;
        else
        {
            while (temp->next_)
                temp = temp->next_;
            temp->next_ = newNode;
        }
        this->size_++;
    }

    bool isEmpty()
    {
        return this->size_ == 0;
    }

    T get(int pos)
    {
        if (this->head_ && pos >= 0 && pos < this->size_)
        {
            Node<T>* temp = this->head_;
            while (pos-- && temp->next_)
                temp = temp->next_;
            return temp->data_;
        }
        else
            throw NonInitializedReference();
    }

    void remove(int pos)
    {
        Node<T>* previous = this->head_;
        Node<T>* current = previous->next_;
        Node<T>* nodeToDelete = 0;

        if (!(pos >= 0 || pos < this->size_))
            return;

        if (pos == 0)
        {
            this->head_ = previous->next_;
            nodeToDelete = previous;
        }
        else
        {
            pos--;
            while (pos-- && current)
            {
                previous = current;
                current = current->next_;
            }
            previous->next_ = current->next_;
            nodeToDelete = current;
        }
        nodeToDelete->next_ = 0;
        delete nodeToDelete;
        this->size_--;
    }

public:
    int size_;
    Node<T>* head_;
};

#endif // GLIST_H

